package com.taiji.dianthus.util;


import org.springframework.beans.factory.annotation.Value;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.*;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import java.util.*;

/**
 * @ClassName AdLDAPUtil
 * @Description
 * @Author H.M
 * @Date 2020/7/10
 */
public class AdLDAPUtil {
    @Value("${ldap.root}")
    private String root;

    @Value("${ldap.group}")
    private Integer group;

    @Value("${ldap.ip}")
    private String adIp;

    @Value("${ldap.username}")
    private String userName;

    @Value("${ldap.password}")
    private String password;

    @Value("${ldap.url}")
    private String ldapUrl;

    @Value("${ldap.user.mail.suffix}")
    private String ldapUserMailSuffix;

    LdapContext dc = null;

    public void init() {
        Hashtable env = new Hashtable();
        String javaHome = System.getProperty("java.home");
        String keystore = javaHome + "/lib/security/cacerts";
        System.out.println("java.home：" + keystore);
        System.setProperty("javax.net.ssl.trustStore", keystore);
        System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
        // LDAP访问地址
        String LDAP_URL = "ldaps://" + ldapUrl;
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        //链接认证服务器
        env.put(Context.SECURITY_PROTOCOL, "ssl");
        env.put(Context.PROVIDER_URL, LDAP_URL);
        //LDAP访问安全级别："none","simple","strong"
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, userName);
        env.put(Context.SECURITY_CREDENTIALS, password);
        try {
            LdapContext ldapContext = new InitialLdapContext(env, null);
            // 这里可以改成异常抛出
            System.out.println("认证成功");
        } catch (javax.naming.AuthenticationException e) {
            System.out.println("认证失败:" + e.toString());
        } catch (Exception e) {
            System.out.println("认证出错：" + e.toString());
        }
    }

    public AdLDAPUtil() {
        super();
        //创建连接
        init();
    }

    public LdapContext getLdapContext() {
        return dc;
    }

    /**
     * @Description:指定搜索节点搜索指定域用户
     * @author moonxy
     * @date 2018-05-15
     */
    public SearchResult searchByUserName(String searchBase, String userName) {
        SearchControls searchCtls = new SearchControls();
        searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        String searchFilter = "sAMAccountName=" + userName;
        //定制返回属性
        String returnedAtts[] = {"memberOf"};
        //设置返回属性集
        searchCtls.setReturningAttributes(returnedAtts);
        try {
            NamingEnumeration<SearchResult> answer = dc.search(searchBase, searchFilter, searchCtls);
            return answer.next();
        } catch (Exception e) {
            System.err.println("指定搜索节点搜索指定域用户失败");
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param base   ：根节点(在这里是"dc=example,dc=com")
     * @param scope  ：搜索范围,分为"base"(本节点),"one"(单层),""(遍历)
     * @param filter ：指定子节点(格式为"(objectclass=*)",*是指全部，你也可以指定某一特定类型的树节点)
     */
    public void searchInformation(String base, String scope, String filter) {
        SearchControls sc = new SearchControls();
        if (scope.equals("base")) {
            sc.setSearchScope(SearchControls.OBJECT_SCOPE);
        } else if (scope.equals("one")) {
            sc.setSearchScope(SearchControls.ONELEVEL_SCOPE);
        } else {
            sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
        }
        NamingEnumeration ne = null;
        try {
            ne = dc.search(base, filter, sc);
            // Use the NamingEnumeration object to cycle through
            // the result set.
            while (ne.hasMore()) {
                System.out.println();
                SearchResult sr = (SearchResult) ne.next();
                String name = sr.getName();
                if (base != null && !base.equals("")) {
                    System.out.println("entry: " + name + "," + base);
                } else {
                    System.out.println("entry: " + name);
                }

                Attributes at = sr.getAttributes();
                NamingEnumeration ane = at.getAll();
                while (ane.hasMore()) {
                    Attribute attr = (Attribute) ane.next();
                    String attrType = attr.getID();
                    NamingEnumeration values = attr.getAll();
                    /*  Vector vals = new Vector();*/
                    // Another NamingEnumeration object, this time
                    // to iterate through attribute values.
                    while (values.hasMore()) {
                        Object oneVal = values.nextElement();
                        if (oneVal instanceof String) {
                            System.out.println(attrType + ": " + (String) oneVal);
                        } else {
                            System.out.println(attrType + ": " + new String((byte[]) oneVal));
                        }
                    }
                }
            }
        } catch (Exception nex) {
            System.err.println("Error: " + nex.getMessage());
            nex.printStackTrace();
        }
    }

    /**
     * @Description:新增AD域用户
     * @author moonxy
     * @date 2018-05-15
     */
    public void add(String newUserName) {
        try {
            Attributes attrs = new BasicAttributes(true);
            attrs.put("objectClass", "user");
            attrs.put("samAccountName", newUserName);
            attrs.put("displayName", newUserName);
            attrs.put("userPrincipalName", newUserName + ldapUserMailSuffix);
            dc.createSubcontext("cn=" + newUserName + "," + root, attrs);
            System.out.println("新增AD域用户成功:" + newUserName);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("新增AD域用户失败:" + newUserName);
        }
    }

    /**
     * 删除
     *
     * @param userName
     */
    public void delete(String userName) {
        try {
            String dn = "CN=" + userName + "," + root;
            dc.destroySubcontext(dn);
            System.out.println("删除成功:");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("删除失败:" + e.toString());
        }
    }

    /**
     * 重命名节点
     *
     * @param oldName
     * @param newName
     * @return
     */
    public boolean renameEntry(String oldName, String newName) {
        String oldDN = "CN=" + oldName + "," + root;
        String newDN = "CN=" + newName + "," + root;
        try {
            Attributes attrs = dc.getAttributes(oldDN);
            if (attrs != null) {
                ModificationItem[] mods = new ModificationItem[1];
                mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,

                        new BasicAttribute("samAccountName", newName));
                dc.modifyAttributes(oldDN, mods);
                dc.rename(oldDN, newDN);
            } else {
                System.out.println("需要修改的节点不存在");
            }
            return true;
        } catch (NamingException ne) {
            System.err.println("Error: " + ne.getMessage());
            return false;
        }
    }

    /**
     * 修改
     *
     * @return
     */
    public boolean modifyInformation(String dn, String employeeID) {
        try {
            System.out.println("开始修改");
            ModificationItem[] mods = new ModificationItem[1];
            /* 修改属性 */
            // Attribute attr0 = new BasicAttribute("employeeID", "W20110972");
            // mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attr0);

            /* 删除属性 */
            // Attribute attr0 = new BasicAttribute("description",
            // "陈轶");
            // mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE,
            // attr0);

            /* 添加属性 */
            Attribute attr0 = new BasicAttribute("employeeID", employeeID);
            mods[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr0);
            /* 修改属性 */
            dc.modifyAttributes(dn + ",dc=example,dc=com", mods);
            System.err.println("修改成功: ");
            return true;
        } catch (NamingException e) {
            e.printStackTrace();
            System.err.println("修改失败: " + e.toString());
            return false;
        }
    }

    /**
     * 修改用户密码
     *
     * @return
     */
    public boolean updatePwd(String newPassword, String userName) {
        try {
            // 初始化ldapcontext
            ModificationItem[] mods = new ModificationItem[1];
            String newQuotedPassword = "\"" + newPassword + "\"";
            byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");
            mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
                    new BasicAttribute("unicodePwd", newUnicodePassword));
            // 修改密码
            dc.modifyAttributes("CN=" + userName + "," + root, mods);
            System.out.println("修改密码成功: " + userName);
        } catch (Exception e) {
            System.out.println("修改密码失败: " + e.toString());
            e.printStackTrace();
        }
        return true;
    }

    /**
     * 修改用户密码
     *
     * @return
     */
    public boolean enableUser(String userName) {
        try {
            // 初始化ldapcontext
            // 修改密码
            Attributes attrs = new BasicAttributes(true);
            attrs.remove("CN");
            attrs.put("userAccountControl", "512");
            ;
            dc.modifyAttributes("CN=" + userName + "," + root, LdapContext.REPLACE_ATTRIBUTE, attrs);
            System.out.println("启用成功: " + userName);
        } catch (Exception e) {
            System.out.println("启用失败: " + e.toString());
            e.printStackTrace();
        }
        return true;
    }

    /**
     * 关闭Ldap连接
     */
    public void close() {
        if (dc != null) {
            try {
                dc.close();
            } catch (NamingException e) {
                System.out.println("NamingException in close():" + e);
            }
        }
    }


    /**
     * 添加用户到组中
     *
     * @param userName
     * @return
     */
    public void addMemberToGroup(String userName, int userType) { //userType 0位学员, 1为教师
        String groupDn = "";
//        if (userType == teaherType) {
//            groupDn = teacherGroup;
//        } else if (userType == studentType) {
//            groupDn = studentGroup;
//        } else {
//            System.out.println("用户没有添加组: " + userName);
//            return;
//        }
        try {
            ModificationItem[] mods = new ModificationItem[1];
            Attribute mod = new BasicAttribute("member", "CN=" + userName + "," + root);
            mods[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, mod);
            dc.modifyAttributes(groupDn, mods);
            System.out.println("用户添加组成功: " + userName);

        } catch (Exception e) {

            System.out.println("用户添加组失败: " + e.toString());

            e.printStackTrace();

        }
    }

    public static String delSpace(String str) throws Exception {
        if (str == null) {
            return null;
        }
        String regStartSpace = "^[　 ]*";
        String regEndSpace = "[　 ]*$";
        // 连续两个 replaceAll
        // 第一个是去掉前端的空格， 第二个是去掉后端的空格
        String strDelSpace = str.replaceAll(regStartSpace, "").
                replaceAll(regEndSpace, "");
        return strDelSpace;
    }


    /**
     * 查询用户是否存在
     *
     * @return
     */
    public boolean isAdUser(String userName) {
        try {
            Attributes attrs = dc.getAttributes("CN=" + userName + "," + root);
            if (attrs == null) {
                return false;
            } else {
                return true;
            }
        } catch (NamingException e) {
            System.out.println(e.toString());
            return false;
        }

    }

    public  String synAdUser(String userName) {
        System.out.println("开始填加Ad域用户");
        AdLDAPUtil adldapUtil = new AdLDAPUtil();
        LdapContext ldapContext = adldapUtil.getLdapContext();
        System.out.println(ldapContext);
        if (ldapContext != null) {
            if (userName != null && !adldapUtil.isAdUser(userName)) {
                adldapUtil.add(userName);
                adldapUtil.updatePwd("123456", userName);
                adldapUtil.enableUser(userName);
                adldapUtil.addMemberToGroup(userName, group);
                adldapUtil.close();
            } else {
                System.out.println("用户名为空");
            }
        } else {
            System.out.println("链接对象为空");
        }
        System.out.println("结束填加Ad域用户");
        return null;
    }
}
